package com.lzx.applib.utils;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

public class LogUtil {

    private static boolean enable = true;
    private static final String TAG = "Lzx";

    public static void enable() {
        enable = true;
    }

    public static void iT(String TAG, Object... msg) {
        if (enable)
            Log.i(TAG, getMsg(msg));
    }

    public static void eT(String TAG, Object... msg) {
        if (enable)
            Log.e(TAG, getMsg(msg));
    }

    public static void vT(String TAG, Object... msg) {
        if (enable)
            Log.v(TAG, getMsg(msg));
    }

    public static void dT(String TAG, Object... msg) {
        if (enable)
            Log.d(TAG, getMsg(msg));
    }

    public static void wT(String TAG, Object... msg) {
        if (enable)
            Log.w(TAG, getMsg(msg));
    }

    public static void i(Object... msg) {
        iT(TAG, getMsg(msg));
    }

    public static void e(Object... msg) {
        eT(TAG, getMsg(msg));
    }

    public static void v(Object... msg) {
        vT(TAG, getMsg(msg));
    }

    public static void d(Object... msg) {
        dT(TAG, getMsg(msg));
    }

    public static void w(Object... msg) {
        wT(TAG, getMsg(msg));
    }

    private static String getMsg(Object... objects) {
        if (objects == null || objects.length == 0)
            return "null";

        StringBuilder msg = new StringBuilder();
        for (int i = 0; i < objects.length; i++) {
            if (msg.length() != 0) {
                msg.append(" ");
            }
            msg.append(objects[i]);
        }
        return msg.toString();
    }

    public static void enter() {
        if (enable) {
            StackTraceElement[] se = Thread.currentThread().getStackTrace();
            StackTraceElement caller = se[3];
            d(caller.getClassName() + ":" + caller.getMethodName() + ":enter");
        }
    }

    public static void exit() {
        if (enable) {
            StackTraceElement[] se = Thread.currentThread().getStackTrace();
            StackTraceElement caller = se[3];
            d(caller.getClassName() + ":" + caller.getMethodName() + ":exit");
        }
    }

    public static void showStack(boolean... all) {
        if (enable) {
            StackTraceElement[] se = Thread.currentThread().getStackTrace();
            d("===============stack start=================");
            for (int i = 3; i < (se.length); i++) {
                if (all.length == 0 || !all[0]) {
                    String className = se[i].getClassName();
                    if (className.startsWith("android")) break;
                }
                d("stack at ", se[i].toString());
            }
            d("===============stack end=================");
        }
    }

    private static long tickTime = 0;

    public static void tick() {
        long curTime = System.currentTimeMillis();
        d("dTime:", curTime - tickTime, "curTime:", curTime);
        tickTime = curTime;
    }

    public static long multiTicks = 0;

    public static void tenTick() {
        multiTicks++;
        if (multiTicks >= 10) {
            multiTicks = 0;
            tick();
        }
    }

    public static void printJSON(String json) {
        try {
            printJSON(new JSONObject(json));
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public static void printJSON(JSONObject json) {
        printJSONObject(json, 1);
    }

    private static String KEY_PAIR = "%s\"%s\":%s,";

    private static void printJSONObject(JSONObject json, int depth) {
        if (json == null) return;

        String depthStr = getDepthString(depth);
        String depthStr2 = getDepthString(depth + 1);

        i(depthStr + "{");
        Iterator<String> keys = json.keys();
        while (keys.hasNext()) {
            String key = (String) keys.next();
            Object value = json.opt(key);

            if (value instanceof JSONObject) {
                if (((JSONObject) value).length() == 0) {
                    i(depthStr2 + key + ":{}");
                } else {
                    i(depthStr2 + key + ":");
                    printJSONObject((JSONObject) value, depth + 1);
                }
            } else if (value instanceof JSONArray) {
                if (((JSONArray) value).length() == 0) {
                    i(depthStr2 + key + ":[]");
                } else {
                    i(depthStr2 + key + ":");
                    printJSONArray((JSONArray) value, depth + 1);
                }
            } else {
                i(String.format(KEY_PAIR, depthStr2, key, value == null ? "null" : value.toString()));
            }
        }
        i(depthStr + "}");
    }

    private static void printJSONArray(JSONArray json, int depth) {
        if (json == null) return;

        String depthStr = getDepthString(depth);
        String depthStr2 = getDepthString(depth + 1);

        i(depthStr + "[");
        for (int i = 0; i < json.length(); i++) {
            Object obj = json.opt(i);
            if (obj instanceof JSONObject) {
                printJSONObject((JSONObject) obj, depth + 1);
            } else if (obj instanceof JSONArray) {
                printJSONArray((JSONArray) obj, depth + 1);
            } else {
                i(depthStr2 + obj + ",");
            }
        }
        i(depthStr + "]");
    }

    private static String getDepthString(int depth) {
        String depthStr = "";
        for (int i = 0; i < depth; i++) {
            depthStr += "  ";
        }
        return depthStr;
    }

    public static void printIntent(Intent intent) {
        String action = intent.getAction();
        i("printIntent: action=" + action);

        String data = intent.getDataString();
        i("printIntent: data=" + data);

        printBundle(intent.getExtras());
    }

    public static void printBundle(Bundle bundle) {
        if (bundle == null) {
            i("printBundle: bundle is empty");
        } else {
            for (String key : bundle.keySet()) {
                i("printBundle: " + key + ":" + bundle.get(key));
            }
        }
    }

    public static void print(Map map) {
        if (map == null) {
            i("Map is null");
        } else if (map.isEmpty()) {
            i("Map is empty");
        } else {
            StringBuilder builder = new StringBuilder();
            Set keys = map.keySet();
            for (Object key : keys) {
                if (builder.length() == 0) {
                    builder.append("Map {\n");
                } else {
                    builder.append(",\n");
                }
                builder.append(key).append(":").append(map.get(key));
            }
            builder.append("\n}");
            i(builder.toString());
        }
    }

    public static <T> void print(List<T> list) {
        print(list.toArray(), "List");
    }

    public static <T> void print(Set<T> set) {
        print(set.toArray(), "Set");
    }

    public static <T> void print(T[] data) {
        print(data, "Array");
    }

    public static void line() {
        i("==================================================================");
    }

    private static <T> void print(T[] data, String info) {
        if (data == null) {
            i(info + " is null.");
        } else if (data.length == 0) {
            i(info + " is empty");
        } else {
            StringBuilder builder = new StringBuilder();
            for (T t : data) {
                if (builder.length() == 0) {
                    builder.append(info).append(" {");
                } else {
                    builder.append(", ");
                }
                if (builder.length() - builder.lastIndexOf("\n") > 50)
                    builder.append('\n');
                builder.append(t);
            }
            builder.append("}");
            i(builder.toString());
        }
    }
}
